package xyz.scootaloo.oj.multithreading.kotlin

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import org.junit.Test
import xyz.scootaloo.common.TestDsl
import kotlin.time.ExperimentalTime
import kotlin.time.measureTime

/**
 * @author flutterdash@qq.com
 * @since 2021/7/5 15:58
 */
@ObsoleteCoroutinesApi
@ExperimentalTime
class Coroutine : TestDsl {

    private val threadName: String
        get() = Thread.currentThread().name

    @Test
    fun test0() = runBlocking {
        val thr = newSingleThreadContext("test0")
        var number = 0
        var sum = 0

        val task_0 = launch {
            val time = measureTime {
                repeat(500) {
                    withContext(thr) {
                        number += 1
                        println("$threadName => $number")
                        sum += number
                    }
                }
            }
//            println(time)
        }

        val task_1 = async {
            repeat(500) {
                withContext(thr) {
                    number += 1
                    println("$threadName => $number")
                    sum += number
                }
            }
        }

        println("task started.")
        task_0.join()
        task_1.join()
        println(sum)
//        thr.close()
    }

    private fun simple(): Flow<Int> = flow { // 流构建器
        for (i in 1..3) {
            delay(100) // 假装我们在这里做了一些有用的事情
            emit(i) // 发送下一个值
        }
    }

    @Test
    fun test1() = runBlocking {
        // 启动并发的协程以验证主线程并未阻塞
        launch {
            for (k in 1..3) {
                println("I'm not blocked $k")
                delay(100)
            }
        }
        // 收集这个流
        simple().collect { value -> println(value) }
    }

    @Test
    fun test2(): Unit = runBlocking {
        launch {
            delay(200L)
            println("Task from runBlocking")
        }


        coroutineScope { // 创建一个协程作用域
            launch {
                delay(500L)
                println("Task from nested launch")
            }
            delay(100L)
            println("Task from coroutine scope") // 这一行会在内嵌 launch 之前输出
        }

        println("Coroutine scope is over") // 这一行在内嵌 launch 执行完毕后才输出
    }

    @Test
    fun timeoutTest(): Unit = runBlocking {
        runCatching {
            withTimeout(1300L) {
                repeat(1000) { i ->
                    println("I'm sleeping $i ...")
                    delay(500L)
                }
            }
        }.getOrElse {
            it.printStackTrace()
        }
    }

}
